﻿export class Uploader {
    constructor(options) {
        this.concurrentNum = options.concurrentNum || 200;//并发数
        this.succeed = 0;//成功数
        this.forIndex = 0;//当前正在上传的片索引
        this.shardCount = 0;//总数
        this.eachIndex = 0;//当前正在上传的片数
        this.shardSize = options.shardSize || 4 * 1024 * 1024;//分片大小
        this.requestId = (new Date().getTime() / 1000).toFixed(0);//请求ID
        this.uploadUrl = options.uploadUrl || '';//上传地址
        this.doneFunc = options.doneFunc || (() => { });//上传完成回调函数
        this.progressElement = options.progressElement; // 假设这是一个进度条的DOM元素选择器
        this.sliderElement = options.sliderElement; // 假设这是layui的slider元素选择器
    }
    resetState() {
        this.succeed = 0;
        this.forIndex = 0;
        this.shardCount = 0;
        this.eachIndex = 0;

    }

    updateProgressUI() {
        $(this.progressElement).html(`${this.succeed} / ${this.shardCount}`);
        layui.slider.render({
            elem: this.sliderElement,
            max: this.shardCount,
            value: this.succeed
        });
    }

    sendData(i, file, count) {
        //计算每一片的起始与结束位置
        const start = i * this.shardSize;
        const end = Math.min(file.size, start + this.shardSize);
        const form = new FormData();
        form.append("data", file.slice(start, end));
        form.append("name", this.requestId + "_" + file.name);
        form.append("total", count);
        form.append("index", i + 1);

        axios.post(this.uploadUrl + "?index=" + i + 1, form, {
            headers: { 'Content-Type': 'multipart/form-data' }
        })
            .then(response => {
                const data = response.data;
                if (data.Code === 1) {
                    console.error(data.Msg);
                }
                else {
                    this.succeed++;
                    this.eachIndex++;
                    this.updateProgressUI();

                    if (this.eachIndex >= this.concurrentNum && this.succeed < this.shardCount) {//大于并发数，并且未完成 继续上传下一批
                        this.scheduleNextBatches(file, count);
                        this.eachIndex = 0;
                    }
                    else if (this.succeed === this.shardCount) {
                        this.doneFunc(data.Msg);
                        this.resetState();
                    }
                }
            })
            .catch(error => {
                console.error('Upload error:', error);
                $("#btnDoUpload").removeAttr("disabled");
            });
    }

    async scheduleNextBatches(file, count, name) {

        const batchSize = Math.min(this.concurrentNum, count - this.succeed);
        for (let i = 0; i < batchSize; ++this.forIndex) {
            await this.sendData(this.forIndex, file, count);
            i++;
        }
        this.eachIndex = 0;
    }

    async upload(files) {
        this.succeed = 0;
        this.forIndex = 0;
        this.shardCount = 0;
        this.eachIndex = 0;

        for (const file of files) {
            const fileSize = file.size || 1;
            this.shardCount += Math.ceil(fileSize / this.shardSize);
        }

        this.updateProgressUI();

        for (const file of files) {
            const fileSize = file.size || 1; // 再次检查，确保计算时不会因文件大小为0而出错
            const count = Math.ceil(fileSize / this.shardSize);
            const xhSize = Math.min(this.concurrentNum, count);
            for (let i = 0; i < xhSize; ++this.forIndex) {
                await this.sendData(this.forIndex, file, count);
                i++;
            }
        }
    }
}
